// HackWarnings.aj
//
// Informatics 102 Spring 2012
// Code Example
//
// This aspect instructs the AspectJ compiler that methods or classes that
// have the @Hack annotation should generate compile-time warnings.  The
// aspect even specifies what the warning message should say.  By either
// including or not including this aspect when compiling our program, we
// can opt to warning when hacks are present or not; it's up to us.
//
// Hacks can either be placed on methods or on classes, so we'll use
// separate pointcuts to match them for clarity.

public aspect HackWarnings
{
	// Notice the appearance of the @Hack annotation before the rest of the
	// signature.  This says "Match any method with a @Hack annotation,
	// regardless of return type, regardless of the name of the class,
	// regardless of the name of the method, and regardless of how many or
	// what types of parameters it takes.
	//
	// Note that it's important that we use the execution() pointcut here
	// instead of call().  The reason is that we want to be sure we warn
	// about "hack" methods whether we call them or not.  The execution()
	// pointcut matches the body of a method, regardless of whether it is
	// called.
	pointcut hackMethods():
		execution(@Hack * *.*(..));


	// Our goal here is to write a pointcut that matches classes that are
	// marked with the @Hack annotation.  We could try the within()
	// pointcut, but it will be too broad; within() matches *every*
	// join point within classes that match a type pattern, which means
	// that every class that contains the @Hack annotation will potentially
	// have many warning messages associated with it.
	//
	// The staticinitialization() pointcut matches the code that is used
	// to initialize the static fields of a class.  There is only one such
	// block of code -- which is generated by default, though you can also
	// write it, as a "static { ... }" block within the class, when
	// necessary.  Either way, staticinitialization() will match one chunk
	// of code associated with any class specified, which makes it a good
	// choice for having one warning on each class that is a hack.
	pointcut hackClasses():
		staticinitialization(@Hack *);
	

	// The "declare warning" declaration reads this way: "Every join point
	// in the following set of pointcuts should cause a compile-time
	// warning with the following message."  In this case, we're saying
	// that hack methods or hack classes should cause warnings.
	//
	// We can replace "declare warning" with "declare error" if we want
	// compile-time errors that will inhibit the program from being
	// compiled successfully and executed.
	//
	// Note that, since they are concerned with whether or not a compile-time
	// warning or error message should be given, "declare warning" and
	// "declare error" cannot be used with dynamic pointcuts such as cflow()
	// and cflowbelow(), which depend on the run-time behavior of a program.
	declare warning:
		hackMethods() || hackClasses():
			"The use of hacks is discouraged; consider rewriting this code";
}
